
package scalaSciCommands;

// this package implements basic commands for the scalaSci's console

import scalaExec.Interpreter.GlobalValues;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import javax.swing.JOptionPane;
import java.lang.reflect.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import java.util.Vector; 
import scala.Option;
import scala.tools.cmd.Instance;
import weka.Instances;

public class BasicCommands {
        public static String commands = "                              \n--------------scalaLab's Basic System Commands ----------------\n\n                      "+
              "\ndir():Unit       :   displays the directory contents" + "\nls()       :   displays the directory contents (as dir())"+
              "\ndirR():Unit       :   recursively displays the directory contents"+ "\nlsR()       :   recursively displays the directory contents"+
              "\ncd(\"directory\"):Unit   : changes the current directory"+
              "\nmd(\"directory\"): creates the specified directory"+
              "\nmkdir(\"directory\"): creates the specified directory"+
              "\ncls()      : clears the display"+
              "\ntic()           : starts the timer"+ "\ntoc()           : retrieves the time passed from the previous tick"+
              "\nString getFile(String initialDirectory, [String messageToUser]): gets a File with a File Dialog, starting at directory initialDirectory, specifying optionally a message to display to the user"+
              " \ndouble getDouble(String messageOfDialogBox, [double defaultValue]): gets a double value with a dialog box, specifying an optional default parameter"+  
              " \nint getInt(String messageOfDialogBox, [int defaultValue]): gets an int  value with a dialog box, specifying an optional default parameter"+
              " \nString getString(String messageOfDialogBox, [String defaultValue]): gets a String value with a dialog box, specifying an optional default parameter"+
              "\n int  load(String fileName) :     // loads the Matlab .mat file contents to scalaSci workspace"+
              "\nboolean  save(String fileName) :      // writes to the Matlab .mat file the contents of the scalaSci workspace"+
              "\nboolean  save(String fileName, String variableNameToSave)"+
              "\nint format(int decPoints)  // controls how many decimal points to display for doubles, sets to decPoints, returns previous setting  "+
              "\n String dump()  // dumps the Scala interpreter state"+
               "\n  def reset():Unit  // resets the Scala interpreter state"+
               "\n  def clear(): Unit // clears the Scala interpreter state without using default imports"+
               "\n String classpath()  // returns the classpath of the Scala interpreter"+
               "\n String appendClasspath(String newPath) // appends the specified path to the classpath of the Scala interpreter if already not exist"+
              "\n String scalaInterpreterWithClassPathComponents() // updates the internal Scala classpath with the ScalaSciClassPath setting"+
              "\n void setMaxPrintString(int numChars ) //sets the interpreter to display at most numChars  "+
              "\n def setTruncate(truncationOn: Boolean):Unit  // controls whether output of  vectors / matrices is truncated"+
              "\n void noTruncate() // i.e. setTruncate(false)"+
              "\n void truncate() // i.e. setTruncate(true)"+
              "\n def setVerboseOn()   // outputs the result to the Console also "+
              "\n def setVerboseOff()   // surpress outputing to the Console"+
               "\n def setMaxMatDisp(value: Int)  // controls how many Mat elements to display"+
               "\n def setMaxMatrixDisp(value: Int)  // controls how many Matrix elements to display"+
               "\n def setVecResizeFactor( newResizeFactor: Double):Double   // sets the Vector resize factor. Returns the previous setting"+
               "\n def setDisplayWorkspaceOn()   // updates the workspace variables"+
              "\n def setDisplayWorkspaceOff()   //  do not update the ScalaSci's workspace"+
              "\n def scatterPlotsOn()   // turns on scatter plotting"+
               "\n def linePlotsOn()    // turns on line plotting"+
               "\n def exec(ScalaScriptFileName: String)  // executes the code in the file ScalaScriptFileName"+
               "\n def eval(String expr): Object  // evaluates the ScalaSci expression passed as a String, e.g. eval(\"var x = rand(1000); plot(x);\")"+
               "\n def inspect(Object obj)   // inspects the object using reflection  "+
               "\n def inspectg(Object obj) // inspects the object graphically  "+
               "\n def displayMatrix(m: Array[Array[Double]]): Unit,  def displayMatrix(m: scalaSci.Matrix): Unit, def displayMatrix(m: scalaSci.Mat): Unit  "+   // displays the contents of the Matrix
               "\n def clearUserPaths() // clears all the user classpaths used by the interpreter "+
               "\n def disp(a: Array[Array[Double]]):Unit    // displays the contents of the double array a "+
               "\n def disp(v: Vec):Unit    // displays the contents of the Vector v "+
               "\n def disp(m: Mat):Mat    // displays the contents of the Mat m"+
               "\n def disp(m: Matrix):Unit    // displays the contents of the Matrix m "+
               "\n def whos() // displays the current workspace "+
               "\n def typeOf() // displays the type of a variable "+
               "\n def readARFFFile(str: String): Array[Array[Double]]"+
               "\n def freeMem():Unit // displays the free memory"+
               "\n def gc(): Unit  // garbage collect";
               //"\n def replay()\n";
               
public static long freeMem()  {
            long frMem = GlobalValues.rt.freeMemory();
            GlobalValues.lastResultOutputArea.setText("Free memory = "+frMem);
            return frMem;
        }
                
public static void gc() { 
    GlobalValues.rt.gc();
}
   // var a = readARFFFile("c:\\test\\quake.arff")
public static double [][]  readARFFFile(String fileName )        {
    Instances instances=null; 
		
	try
		{
	FileReader  arffReader = new FileReader(fileName);
	instances = new Instances(arffReader);
	 }
     catch (Exception e)
	 {
	System.out.println("ReadARFF: I/O exception");
	}		    
	int nInstances = instances.numInstances();
	int nAttribs = instances.numAttributes();
	double [][] values = new double[nInstances][nAttribs];
	for (int inst=0; inst<nInstances; inst++) {
		weka.Instance  currentInstance = instances.instance(inst);
		for (int attr=0; attr<nAttribs; attr++) 
		   values[inst][attr]  = currentInstance.value(attr);
		}

         return values;
}

        public static void replay() {
            
        }

        public static void disp( double [][] a)  {
            int N = a.length;
            int M = a[0].length;
            for (int n=0; n<N; n++) {
                for (int m=0; m<M; m++)
                    System.out.print(a[n][m]+"  ");
                    System.out.println();
              }
        }
        
        public static void disp( scalaSci.Vec a)  {
            System.out.println("Vector contents: \n");
            double [] av = a.getv();
            for (int m=0; m<a.length(); m++)
                 System.out.print(av[m]+"  ");
        }
        
        public static void disp( scalaSci.Mat m)  {
            System.out.println("Zero-indexed Matrix contents: \n");
            disp(m.getv());
        }
        
        public static void disp( scalaSci.Matrix m)  {
            System.out.println("One-indexed Matrix contents: \n");
            disp(m.getv());
        }
        
        public static void clearUserPaths() {
            GlobalValues.clearUserPaths();
        }
        
        public static void displayMatrix( double [][] matrix) {
            scalaExec.gui.watchMatrix.display(matrix, false);
        }
        
        public static void displayMatrix( scalaSci.Matrix  matrix) {
            scalaExec.gui.watchMatrix.display(matrix.getv(), true);
        }
      
        public static void displayMatrix( scalaSci.Mat  matrix) {
            scalaExec.gui.watchMatrix.display(matrix.getv(), false);
        }
      
        
        public static void inspect(Object obj)  {
            Inspect.inspect(obj);
        }

        public static void inspectg(Object obj)  {
            Inspect.inspectg(obj);
        }

        public static   void setVerboseOn()  {
           GlobalValues.displayCommandScalaSciBinding = true;
           GlobalValues.globalVerboseOff = false;
        }

 public static   void setVerboseOff()  {
            GlobalValues.displayCommandScalaSciBinding = false;
            GlobalValues.globalVerboseOff = true;
        }
        
 public static void dumpState() {
     System.out.println("dumpState: ");
     //GlobalValues.scalalabMainFrame.scalalabConsole.scalaInterpreter.dumpValAndVarNames();
 }
public static Object eval(String expr)  {
    scala.tools.nsc.InterpreterResults.Result res = GlobalValues.scalalabMainFrame.scalalabConsole.scalaInterpreter.interpret(expr);
    return res; 
}

public static void whos() {
    GlobalValues.scalalabMainFrame.scalalabConsole.scalaInterpreter.printAllTypeOf();
}

public static Option<String> typeOf(String ident) {
    return GlobalValues.scalalabMainFrame.scalalabConsole.scalaInterpreter.typeForIdent(ident);
}

// # eval("var kk = k"); var hh = 7*kk
public static Integer  getIntValue(String varName)  {  // gets the value of the variable varName if it was defined
    String  evalExpr = "var  vv ="+varName;
    Object rv =  eval(evalExpr);  
    return   (Integer)rv;
}
 
         
 public static   void setDisplayWorkspaceOn()  {
            GlobalValues.displayScalaSciBindingGlobal = true;
        }
   
        
 public static   void setDisplayWorkspaceOff()  {
            GlobalValues.displayScalaSciBindingGlobal = false;
        }
        
              
         // controls how many decimal points to display for doubles, sets to decPoints, returns previous setting
  public static int format(int decPoints)   {
            int prevFmtLen = GlobalValues.doubleFormatLen;
            GlobalValues.doubleFormatLen = decPoints;
            String s="0.";
            for (int k=0; k<decPoints;k++)  s +="0";
            GlobalValues.fmtString = new DecimalFormat(s);
            GlobalValues.fmtMatrix = GlobalValues.fmtString;
            GlobalValues.fmtString.setDecimalFormatSymbols(new DecimalFormatSymbols(new Locale("us")));
            GlobalValues.fmtMatrix.setDecimalFormatSymbols(new DecimalFormatSymbols(new Locale("us")));
            return prevFmtLen;
        }
                
  public static String tic() {    
      GlobalValues.timeForTic = System.currentTimeMillis();   // save the current time
        return  Long.toString(GlobalValues.timeForTic);
  }

  public static String toc() {
         double delay = (double)(System.currentTimeMillis()-GlobalValues.timeForTic)/1000.0;
        return Double.toString(delay);
  }
//double sm=0.0d; int  k1=1; tic(); while (k1 < 1000000) { sm = (0.0002/(double)k1); k1++; };  String  tm = toc(); System.out.println("sm = "+sm+",   tm = "+tm);

  public static void cls() {
              GlobalValues.scalalabMainFrame.scalalabConsole.clearConsole();
   }
  
  public static void help() {
              GlobalValues.scalalabMainFrame.scalalabConsole.setText(commands);
   }
  
  public static void disp(String str) {
         System.out.println(str);
  }

        
  
  public static  void cd(String  newDirectory)    {
      if (newDirectory.equals(".."))  {   // change to "upper" directory
          String currentDirectory = GlobalValues.workingDir;
          int pathSepIndex = currentDirectory.lastIndexOf(File.separatorChar);
          currentDirectory = currentDirectory.substring(0, pathSepIndex);
          newDirectory = currentDirectory;
      }
      try {
      File dir=null;
	if (newDirectory.charAt(0)==File.separatorChar 	|| newDirectory.charAt(1)==':')   
	     dir = new File(newDirectory); 	// absolute file path name
	else  // relative path name to the current working directory
             dir = new File(GlobalValues.workingDir, newDirectory);  
		 	
		if (dir.isDirectory())
	              GlobalValues.workingDir = dir.toString();  // set the new system's current directory		
		}
		catch (Exception e)
		{
			System.out.println("cd: IO exception");
		}		    
       
  }

  public static void mkdir(String newDirectory) {
      md(newDirectory);
  }

  public static  void md(String  newDirectory)    {
       try {
                File fNewDirectory = null;
                String newDirectoryFullPathName = newDirectory;

      if (newDirectory.charAt(0)==File.separatorChar 	|| newDirectory.charAt(1)==':')
	     fNewDirectory = new File(newDirectory); 	// absolute file path name
	else  // relative path name to the current working directory
     {
	                // create the specified directory actually at the filesystem
                String directoryPath = GlobalValues.workingDir;

                newDirectoryFullPathName = directoryPath+File.separator+newDirectory;
                fNewDirectory = new File(newDirectoryFullPathName);
    }

                int userResponse = JOptionPane.YES_OPTION;
                boolean  dirExists = fNewDirectory.exists();
                if (dirExists)     // directory already exists
                     JOptionPane.showMessageDialog(null, "Directory: "+newDirectoryFullPathName+" already exists");

                if (dirExists==false)   {  // create new directory and update tree
                    // create new directory
                     try {
               fNewDirectory.mkdir();  // creates the corresponding directory
                     }
                     catch (SecurityException ioEx)  {
    JOptionPane.showMessageDialog(null, "IOException trying to create file"+newDirectoryFullPathName, "IO Exception", JOptionPane.INFORMATION_MESSAGE );
                     }


      if (fNewDirectory.isDirectory())
	              GlobalValues.workingDir = fNewDirectory.toString();  // set the new system's current directory
		}
       }

                catch (Exception e)
		{
			System.out.println("cd: IO exception");
		}

  }

  

  public static String dir()  {
        StringBuilder sb = new StringBuilder();
        String directoryToDisplay;
        directoryToDisplay = GlobalValues.workingDir;
        
        try {
        File pathName = new  File(directoryToDisplay);
        String [] fileNames = pathName.list();
        
        // enumerate all files in the directory
        for (int i=0; i<fileNames.length; i++)
        {
            File f = new File(pathName.getPath(), fileNames[i]);
            if (f.isDirectory())
                sb.append("\n "+fileNames[i]+"    <dir>");
            else
                sb.append("\n"+fileNames[i]);
         }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return sb.toString();
  }
    
  
    public static String ls()  {   // for UNIX users
        return dir();
  }
    
   public static String lsR()  {   // for UNIX users
        return dirR();
  }

   public static String lsR(String directory)  {   // for UNIX users
        return dirR(directory);
  }

    public static String dir(String directory)  {
        StringBuilder sb = new StringBuilder();
        String directoryToDisplay;
        if (directory == "")   
             directoryToDisplay = GlobalValues.workingDir;
        else  // the user has specified a directory, i.e. dir  <directoryToDisplay> 
             directoryToDisplay = directory; 
        
        try {
        File pathName = new  File(directoryToDisplay);
        String [] fileNames = pathName.list();
        
        // enumerate all files in the directory
        for (int i=0; i<fileNames.length; i++)
        {
            File f = new File(pathName.getPath(), fileNames[i]);
            if (f.isDirectory())  
                sb.append("\n "+fileNames[i]+"    <dir>");
            else
                sb.append("\n"+fileNames[i]);
         }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return sb.toString();
  }
    
    
    // recursively display the contents of the subdirectories
   public static String dirR(String directory)  {
        StringBuilder sb = new StringBuilder();
        String currentWorkingDirectory = directory;
        
        try {
        File pathName = new  File(currentWorkingDirectory);
        String [] fileNames = pathName.list();
        
        // enumerate all files in the directory
        for (int i=0; i<fileNames.length; i++)
        {
            File f = new File(pathName.getPath(), fileNames[i]);
            if (f.isDirectory())  {
                sb.append("\n "+fileNames[i]+"    <dir>");
                String nested = dirR(fileNames[i]);
                sb.append("\n\n"+nested+"\n\n");
             }
            else
                sb.append("\n"+fileNames[i]);
         }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return sb.toString();
        }
   
    // recursively display the contents of the subdirectories
   public static String dirR()  {
        StringBuilder sb = new StringBuilder();
        String currentWorkingDirectory = GlobalValues.workingDir;
        
        try {
        File pathName = new  File(currentWorkingDirectory);
        String [] fileNames = pathName.list();
        
        // enumerate all files in the directory
        for (int i=0; i<fileNames.length; i++)
        {
            File f = new File(pathName.getPath(), fileNames[i]);
            if (f.isDirectory())  {
                sb.append("\n "+fileNames[i]+"    <dir>");
                String nested = dirR(currentWorkingDirectory+File.separatorChar+fileNames[i]);
                sb.append("\n\n"+nested+"\n\n");
             }
            else
                sb.append("\n"+fileNames[i]);
         }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return sb.toString();
        }
   
public static double getDouble(String msg)  {
    String strMsg = JOptionPane.showInputDialog(msg);
    double val = Double.valueOf(strMsg);
    return val;
}

public static double getDouble()  {
    String strMsg = JOptionPane.showInputDialog("Give double value");
    double val = Double.valueOf(strMsg);
    return val;
}

public static int  getInt(String msg)  {
    String strMsg = JOptionPane.showInputDialog(msg);
    int val = Integer.valueOf(strMsg);
    return val;
}

public static int  getInt()  {
    String strMsg = JOptionPane.showInputDialog("Give int value");
    int val = Integer.valueOf(strMsg);
    return val;
}


public static String getString(String msg)  {
    String strMsg = JOptionPane.showInputDialog(msg);
    return  strMsg;
}

public static String getString()  {
    String strMsg = JOptionPane.showInputDialog("Give String value");
    return  strMsg;
}

public static double getDouble(String msg, double defaultVal)  {
    String strMsg = JOptionPane.showInputDialog(msg, Double.toString(defaultVal));
    double val = Double.valueOf(strMsg);
    return val;
}


public static int  getInt(String msg, int defaultVal)  {
    String strMsg = JOptionPane.showInputDialog(msg, Integer.toString(defaultVal));
    int val = Integer.valueOf(strMsg);
    return val;
}


public static String getString(String msg, String defaultVal)  {
    String strMsg = JOptionPane.showInputDialog(msg,  defaultVal);
    return  strMsg;
}

public static String getFile() {
    javax.swing.JFileChooser chooser = new javax.swing.JFileChooser(GlobalValues.workingDir);
    chooser.setDialogTitle("Specify file for loading data");
    chooser.setVisible(true);
    chooser.showOpenDialog(GlobalValues.scalalabMainFrame);
    File file = chooser.getSelectedFile();
    return file.getAbsolutePath();   // the full file name
}  

public static String getFile(String dir) {
    javax.swing.JFileChooser chooser = new javax.swing.JFileChooser(dir);
    chooser.setDialogTitle("Specify file for loading data");
    chooser.setVisible(true);
    chooser.showOpenDialog(GlobalValues.scalalabMainFrame);
    File file = chooser.getSelectedFile();
    return file.getAbsolutePath();   // the full file name
}  

public static String getFile(String dir, String messageToUser) {
    javax.swing.JFileChooser chooser = new javax.swing.JFileChooser(dir);
    chooser.setDialogTitle(messageToUser);
    chooser.setVisible(true);
    chooser.showOpenDialog(GlobalValues.scalalabMainFrame);
    File file = chooser.getSelectedFile();
    return file.getAbsolutePath();   // the full file name
}  

public static  Object arrayGrow( Object o)  {
    Class  cl = o.getClass();
    if (!cl.isArray() )   return  null;
    Class componentType = cl.getComponentType();
    int  length = Array.getLength(o);
    int  newLength = length * 11 / 10 + 10;
    
    Object newArray = Array.newInstance(componentType, newLength);
    System.arraycopy(o, 0,  newArray, 0, length);
    return newArray;
}

public static String dump() {
    //String scalaInterpreterState = GlobalValues.scalalabMainFrame.scalalabConsole.scalaInterpreter.dumpBoundNames();

    return ""; //scalaInterpreterState;
}

// reset the Scala interpreter
public static void reset() {
 GlobalValues.scalalabMainFrame.scalalabConsole.createInterpreterForReset();
}

public static void clear() {
 GlobalValues.scalalabMainFrame.scalalabConsole.createInterpreterForReset();
}



public static String classpath() {
    scala.collection.immutable.List <URL> classp = GlobalValues.scalalabMainFrame.scalalabConsole.scalaInterpreter.compilerClasspath();
    return classp.toString();
}

public static String appendClasspath(String newPath) {
   // construct and initialize a new Scala Interpreter with appended classpath that includes the 'newPath'   
    newPath = newPath.trim();
    GlobalValues.scalalabMainFrame.scalalabConsole.interpreterWithAppendedCP(newPath);
  // update also the GUI ScalaSciClassPathComponents parameter to include the new path   
    if (GlobalValues.ScalaSciClassPathComponents.indexOf(newPath)==-1)  {
     GlobalValues.ScalaSciClassPathComponents.add(newPath);
     scalaExec.scalaLab.scalaLab.updateTree();
     }
    // return the appended classpath
    return classpath();
}

public static String appendClasspaths(String [] newPaths) {
    int len = newPaths.length;
            
   // construct and initialize a new Scala Interpreter with appended classpath that includes the 'newPath'   
    GlobalValues.scalalabMainFrame.scalalabConsole.interpreterWithAppendedCP(newPaths);
  // update also the GUI ScalaSciClassPathComponents parameter to include the new path   
  for (int k=0; k<newPaths.length; k++)
    if (GlobalValues.ScalaSciClassPathComponents.contains(newPaths[k])==false)
        GlobalValues.ScalaSciClassPathComponents.add(newPaths[k].trim());
    
     scalaExec.scalaLab.scalaLab.updateTree();   
       // return the appended classpath
    return classpath();
}

public static String appendClasspaths(Vector newPaths) {
    int len = newPaths.size();

   // construct and initialize a new Scala Interpreter with appended classpath that includes the 'newPath'
    GlobalValues.scalalabMainFrame.scalalabConsole.interpreterWithAppendedCP(newPaths);
  // update also the GUI ScalaSciClassPathComponents parameter to include the new path
  for (int k=0; k<newPaths.size(); k++)
    if (GlobalValues.ScalaSciClassPathComponents.contains(newPaths.elementAt(k))==false)
        GlobalValues.ScalaSciClassPathComponents.add(newPaths.elementAt(k));

     scalaExec.scalaLab.scalaLab.updateTree();
       // return the appended classpath
    return classpath();
}

// creates a new Scala Interpreter that is initialized to include all the ScalaSciClassPathComponents in its classpath
public static String  scalaInterpreterWithClassPathComponents() {
    int cplen = GlobalValues.ScalaSciClassPathComponents.size();
    String [] cpElems = new String[cplen];
    for (int k=0; k < cplen; k++) 
        cpElems[k] = (String) GlobalValues.ScalaSciClassPathComponents.elementAt(k);
    GlobalValues.scalalabMainFrame.scalalabConsole.interpreterWithAppendedCP(GlobalValues.ScalaSciClassPathComponents);
   scalaExec.scalaLab.scalaLab.updateTree(); 
return classpath();
}

public static  void setMaxPrintString(int value) // causes the interpreter to print the full output results without truncated"+
{
   //scala.tools.nsc.Interpreter$.MODULE$.maxPrintStringSize_$eq(value);
}

public static  void setMaxMatDisp(int value)  // controls how many mat elements to display
{
    scalaSci.Mat$.MODULE$.mxElemsToDisplay_$eq(value);
}

public static void setMaxMatrixDisp(int value)    // controls how many matrix elements to display
{
    scalaSci.Matrix$.MODULE$.mxElemsToDisplay_$eq(value);
}

public static  void setTruncate(boolean truncationOn) {
      GlobalValues.truncateOutput = truncationOn;
      /*if (truncationOn == false)
        scala.tools.nsc.Interpreter$.MODULE$.maxPrintStringSize_$eq(-1);
      else
       scala.tools.nsc.Interpreter$.MODULE$.maxPrintStringSize_$eq(300);
         */
}

public static void noTruncate() 
{
    setTruncate(false);
}


public static void truncate() 
{
    setTruncate(true);
}


   public static void exec(String fileName)  {

        if (fileName.indexOf(File.separatorChar)==-1)  // not absolute path: append current directory
           fileName = GlobalValues.workingDir+File.separator+fileName;
       
       if (fileName.indexOf(".")==-1)  // append as default extension ".scala"
           fileName = fileName+".scala";
       
   if (fileName != null) {  // load the contents of the file at the editor's textArea for editing
       int idxDir = fileName.indexOf(File.separatorChar);
          try {
      File file = new File(fileName);
      FileReader fr = new FileReader(file);
      BufferedReader in = new BufferedReader(fr);
      int MaxBufLen = (int) file.length();
      char [] cbuf = new char[MaxBufLen];
      in.read(cbuf, 0, MaxBufLen);
      String textIn = String.valueOf(cbuf);
      GlobalValues.scalalabMainFrame.scalalabConsole.interpretLine(textIn);
            }
    catch (Exception e) {
      System.out.println("Cannot read file "+fileName);
    }
  }
        
  }
   
}
   
